package RDA;

import java.io.File;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class RDAWindow extends JFrame implements ChangeListener,FileModfiyMonitor.AlarmEvent  {

    public static void main(String[] args) {
        RDAWindow window =  new RDAWindow();


        ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(5);
        // 定时执行任务 client 维护任务
        executorService.scheduleAtFixedRate(window.clietMaintainTask, 5000, 2000,TimeUnit.MILLISECONDS);
        // 定时执行报警检测任务
        executorService.scheduleAtFixedRate(window.CheckFileTask,1000,1000,TimeUnit.MILLISECONDS);
        // 线程任务,
        Thread thread = new Thread(window.HeartTask);
        thread.start();
    }

    private boolean TestEnable = false;
    ArrayList<RDAClient> clients = new ArrayList<RDAClient>();
    private FileModfiyMonitor  fileModfiyMonitor = null;

    private JTextArea heartStatusLable;
    private JTextArea CheckAlarmStatusLabel;
    public  RDAWindow(){
        long initD = 0;
        try {
            Date utc = getCurrentUtcTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(utc);
            int year = calendar.get(Calendar.YEAR);
            int mouth = calendar.get(Calendar.MONTH)+1;
            int day = calendar.get(Calendar.DAY_OF_MONTH);
            String file = String.format("/opt/rda/log/%4d%02d%02d_Alarm.log",year,mouth,day);
            initD =  FileModfiyMonitor.getLastModify(file);
        }catch (Exception ex){
            ex.printStackTrace();
        }
        fileModfiyMonitor = new FileModfiyMonitor(initD);
        fileModfiyMonitor.setAlarmEvent(this);

        /*设置显示窗口标题*/
        setTitle("雷达报警监控@威海市气象局");
        //设置窗口显示尺寸
        setSize(800,400);
        //置窗口是否可以关闭
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //创建面板
        JPanel panel=new JPanel();
        // 3行1列布局
        panel.setLayout(new GridLayout(3,1,0,10));

        JPanel innerPanel1 = new JPanel(new GridLayout(2,1));
        // 测试复选框
        JCheckBox TestCheckbox = new JCheckBox("测试模式",false);
        TestCheckbox.addChangeListener(this);
        JTextArea TestTip = new JTextArea("打开测试共后，会监控\"RadarMonitorTest.txt\"文件，修改该文件可以触发报警。\r\n注意，修改后的文件的最后一行必须包含\"ALARM\"字符才会被认为是报警！",3,1);
        TestTip.setLineWrap(true);
        innerPanel1.add(TestCheckbox);
        innerPanel1.add(TestTip);
        panel.add(innerPanel1);

        //创建一个标签
        heartStatusLable = new JTextArea("",2,1);
        heartStatusLable.setLineWrap(true);
        panel.add(heartStatusLable);

        CheckAlarmStatusLabel = new JTextArea("",2,1);
        CheckAlarmStatusLabel.setLineWrap(true);
        panel.add(CheckAlarmStatusLabel);

        add(panel);
        setBounds(0,0,800,400);
        setVisible(true);
    }

    /**
     * 获取UTC时间
     * @return utc date
     * @throws ParseException 异常
     */
    private static Date getCurrentUtcTime() throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        SimpleDateFormat localDateFormat = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
        return localDateFormat.parse( simpleDateFormat.format(new Date()) );
    }

    /**
     * 测试复选项变化
     * @param e evenr
     */
    @Override
    public void stateChanged(ChangeEvent e) {
        JCheckBox checkBox = (JCheckBox) e.getSource();
        TestEnable = checkBox.isSelected();
    }

    /**
     * 接收心跳任务
     */
    private Runnable HeartTask = new Runnable() {
        @Override
        public void run() {
            byte[] buf=new byte[4096];
            DatagramPacket dpReceive=null;
            DatagramSocket udpServer=null;
            while (true){
                try {
                    udpServer  = new DatagramSocket(14081);
                    SwingUtilities.invokeLater(new Runnable() {
                        @Override
                        public void run() {
                            heartStatusLable.setText("心跳服务启动完成");
                        }
                    });
                    while (true){
                        dpReceive=new DatagramPacket(buf, buf.length);
                        try {
                            udpServer.receive(dpReceive);
                            InetAddress ip = dpReceive.getAddress();
                            int port = dpReceive.getPort();
                            RDAClient client = new RDAClient(ip.getHostAddress(),port,0);
                            int index = clients.indexOf(client);
                            if(index==-1){ //新链接
                                clients.add(client);
                            }else {
                                clients.get(index).timeout = 0;
                            }

                            // send back
                            String response = "RDA_Monitor\r\n\0";
                            byte[] responseBuf = response.getBytes();
                            DatagramPacket responsePacket = new DatagramPacket(responseBuf,responseBuf.length,ip,port);
                            try{
                                //发送数据
                                udpServer.send(responsePacket);
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                            // 更新UI
                            final String ipS = ip.getHostAddress();
                            SwingUtilities.invokeLater(new Runnable() {
                                @Override
                                public void run() {
                                    heartStatusLable.setText("收到"+ ipS +"的心跳"+"："+ (new Date()));
                                }
                            });

                        }catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                } catch (SocketException e) {
                    e.printStackTrace();
                }finally {
                    if(udpServer!=null){
                        udpServer.close();
                        udpServer = null;
                    }
                }
                //  启动失败
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        heartStatusLable.setText("心跳服务启动失败");
                    }
                });

                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };

    /**
     * 定期删除不在线的client 任务
     */
    private Runnable clietMaintainTask = new Runnable() {
        @Override
        public void run() {
            try {
                //处理超时的连接
                ArrayList<RDAClient> willRemove = new ArrayList<RDAClient>();
                for (RDAClient cl :
                        clients) {
                    cl.timeout ++;
                    if(cl.timeout >7){
                        willRemove.add(cl);
                        System.out.println("删除Client"+cl.ip+":"+cl.port);
                    }
                }
                clients.removeAll(willRemove);
                /*  Java8 API
                clients.removeIf(new Predicate<RDAClient>() {
                    @Override
                    public boolean test(RDAClient rdaClient) {
                        boolean res =  rdaClient.timeout >7; //2s进行一次清理，大约15s
                        return res;
                    }
                });
                */

            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    };

    /**
     * 检测文件
     */
    private Runnable CheckFileTask = new Runnable() {
        @Override
        public void run() {
            try {
                if(fileModfiyMonitor ==null){
                    return;
                }

                String file = null;
                if(TestEnable){
                    file= "RadarMonitorTest.txt";
                }else {
                    Date utc = getCurrentUtcTime();
                    Calendar calendar = Calendar.getInstance();
                    calendar.setTime(utc);
                    int year = calendar.get(Calendar.YEAR);
                    int mouth = calendar.get(Calendar.MONTH)+1;
                    int day = calendar.get(Calendar.DAY_OF_MONTH);
                    file = String.format("/opt/rda/log/%4d%02d%02d_Alarm.log",year,mouth,day);

                }
                final String afile = (new File(file)).getAbsoluteFile().toString();
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        CheckAlarmStatusLabel.setText("检测" + afile +" : "+(new Date()));
                    }
                });
                fileModfiyMonitor.checkFile(file);

            } catch (ParseException e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        CheckAlarmStatusLabel.setText("获取UTC时间失败: "+(new Date()));
                    }
                });
                e.printStackTrace();
            }
        }
    };

    /**
     * 检测到文件有最新更改
     * @param msg 文件最后一行
     */
    @Override
    public void alarm(final String path,final String msg){
        //todo 发送报警通知
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                CheckAlarmStatusLabel.setText("检测" + path +":"+(new Date()) + "\r\n"+ "报警："+ msg);
            }
        });

        for (RDAClient cl:
             clients) {
            try {
                // 创建客户端的DatagramSocket对象，不必传入地址和对象
                DatagramSocket udpClient = new DatagramSocket();
                byte[] sendBytes = msg.getBytes();
                //封装要发送目标的地址
                InetAddress address = InetAddress.getByName(cl.ip);
                //封装要发送的DatagramPacket的对象，由于要发送到目的主机，所以要加上地址和端口号
                DatagramPacket sendPacket = new DatagramPacket(sendBytes,sendBytes.length,address,cl.port);
                try {
                    //发送数据
                    udpClient.send(sendPacket);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
    }
}
